Skip to content

Migrate from BotFramework to TeamsSDK#302

Open
heyitsaamir wants to merge 12 commits intovercel:mainfrom
heyitsaamir:aamir/teams-sdk-migration
Open

Migrate from BotFramework to TeamsSDK#302
heyitsaamir wants to merge 12 commits intovercel:mainfrom
heyitsaamir:aamir/teams-sdk-migration

Conversation

@heyitsaamir
Copy link

@heyitsaamir heyitsaamir commented Mar 26, 2026

Hello! I am the maintainer for TeamsSDK, which is the official SDK for Microsoft Teams. We noticed that y'all are using BotFramework in the adapter here which is actually now deprecated. We took the initiative to migrate you guys over to TeamsSDK. Hope that's okay!

Some wins:

  • Port to our SDK which is now being actively maintained.
  • Better type safety all around - we have better type safety not only for Teams entities, but also Graph so the adapter doesn't need to maintain Graph types).
  • Less code for setup
  • Reactions support

Pending:

  • I need to go through all the unit tests that y'all had and make sure I'm not missing any major ones. I manually tested everything so it should be okay, but will add UTs as well.

What didn't make it:

  • We don't really support Certificates. We have client-secret support, User managed identity support, and Federated Identity Credentials support. But no certs. If someone really wanted it, then can pass their own token generator as part of token option (which is basically a factory that generates a token). Our general logic was that if someone is using certs, they might as well just use secrets.
  • I changed the AdapterOptions to be closer to what TeamsSDK App has instead of what BotFrameworked has. If we want to maintain backward compatibility, I'm happy to keep that outward facing interface and map to our App options.

Some things I would like to add in a followup (or even in this):

  • Simpler code - 1 giant file is hard for me and Claude to work through :) Wanted an okay from someone on the team here before I move some code to their own smaller files.
  • I would like to migrate the cards logic over to our cards package as well which also offers better type safety over just raw jsons.
  • We have modal support as well. I'd like to add support for that next.
  • I know the setup is inconvenient right now, so we are working on a solution improve that as well.

Summary

Test plan

Tested the scenarios in the example bot.
Eg Channels:
image

DMs:
image

(Happy to share more screenshots / video if needed).

heyitsaamir and others added 6 commits March 25, 2026 16:29
Replace botbuilder/botframework-connector with @microsoft/teams.apps (TeamsSDK v2.0.6).

Breaking changes:
- Remove certificate auth (TeamsAuthCertificate) — use token or managedIdentityClientId instead
- Env vars changed: TEAMS_APP_ID → CLIENT_ID, TEAMS_APP_PASSWORD → CLIENT_SECRET, TEAMS_APP_TENANT_ID → TENANT_ID
- Reactions now work (addReaction/removeReaction) instead of throwing NotImplementedError
- Graph API calls use @microsoft/teams.graph-endpoints typed endpoints

Key changes:
- BridgeHttpAdapter captures TeamsSDK route handler for serverless dispatch
- Event handlers registered via app.on() (message, messageReaction, card.action, conversationUpdate, installationUpdate)
- Outbound calls use app.send() and app.api.conversations.activities()
- Stream support via post+edit (native HttpStream when SDK exports it)
- Graph API uses typed endpoints from @microsoft/teams.graph-endpoints
- isMention detection via activity entities instead of bot name matching

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace custom config fields with Pick<AppOptions, ...>
  clientId (was appId), clientSecret (was appPassword), tenantId (was appTenantId)
- Remove TeamsAuthFederated, appType — use managedIdentityClientId directly
- Constructor passes config through to App (App handles env var resolution)
- Use this.app.id instead of this.config.appId for bot identity checks
- 3 replay-fetch-messages tests have known failures (type shape mismatch)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove useless private api() getter, use this.app.api directly
- Type handlers with specific activity types:
  handleMessageActivity(ctx: IActivityContext<IMessageActivity>)
  handleAdaptiveCardAction(ctx: IActivityContext<IAdaptiveCardActionInvokeActivity>)
  handleReactionFromContext(ctx: IActivityContext<IMessageReactionActivity>)
- Remove unnecessary casts now that ctx.activity is properly typed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keep Azure OpenAI and DM handler changes as local-only, not part of the migration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keep only adapters.ts config changes, revert package.json dep changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Contributor

vercel bot commented Mar 26, 2026

@heyitsaamir is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

@heyitsaamir heyitsaamir changed the title Aamir/teams sdk migration Migrate from BotFramework to TeamsSDK Mar 26, 2026
heyitsaamir and others added 4 commits March 25, 2026 18:17
- New env vars: CLIENT_ID, CLIENT_SECRET, TENANT_ID
- New config: clientId, clientSecret, tenantId, token, managedIdentityClientId
- Remove certificate auth docs (dropped)
- Reactions now supported (add/remove)
- Typing indicator now supported
- Graph API uses @microsoft/teams.graph-endpoints
- Note streaming and modals status

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bensabic bensabic requested a review from cramforce March 26, 2026 09:44
@bensabic
Copy link
Contributor

Hey @heyitsaamir!

Thank you so much for this.

Quick comment: would you be able to also add support for Task Modules?

@heyitsaamir
Copy link
Author

Hey @heyitsaamir!

Thank you so much for this.

Quick comment: would you be able to also add support for Task Modules?

Yes! Would you like me to add that in this same pr or follow up? My plan was on a follow up.

@reliccare reliccare mentioned this pull request Mar 26, 2026
1 task
Split the 2,114-line index.ts into focused modules:
- types.ts: TeamsAdapterConfig, TeamsThreadId, TeamsChannelContext
- errors.ts: handleTeamsError as standalone pure function
- graph-api.ts: TeamsGraphReader class with all Graph API read methods

index.ts shrinks to ~1,133 lines, delegating graph reads to TeamsGraphReader
which receives dependencies via constructor injection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@heyitsaamir
Copy link
Author

@bensabic Created this Issue when it comes to modals on Teams - #306. Lmk what you think!

@vercel vercel deleted a comment from AntonVishal Mar 26, 2026
@vercel vercel deleted a comment from heyitsaamir Mar 26, 2026
@bensabic
Copy link
Contributor

@heyitsaamir I wasn't sure what they meant either, looked like spam or a bot—just deleted the comments to reduce noise.

Thank you for the very detailed issue, I just replied to it for the sake of the PR thread being cleaner. It makes sense why modals support would need to be in a separate PR, since the underlying mechanics itself for how we handle modals would have to be tweaked slightly.

Unrelated: does the Teams SDK have support for slash commands? That would be amazing if so. As the dream is for all adapters to be as close together as possible in terms of functionality.

@heyitsaamir
Copy link
Author

@heyitsaamir I wasn't sure what they meant either, looked like spam or a bot—just deleted the comments to reduce noise.

Thank you for the very detailed issue, I just replied to it for the sake of the PR thread being cleaner. It makes sense why modals support would need to be in a separate PR, since the underlying mechanics itself for how we handle modals would have to be tweaked slightly.

Unrelated: does the Teams SDK have support for slash commands? That would be amazing if so. As the dream is for all adapters to be as close together as possible in terms of functionality.

Sweet. I'm happy to put up a PR stacked on this, or once this goes in (if y'all are okay with it).

As for slash commands - we currently have a version of it:
https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/create-a-bot-commands-menu?tabs=desktop%2Cjavascript
Here, it will suggest some slash commands for the user, and you declare them in your manifest. But triggering them essentially just dumps the command in your compose box. And the user needs to send them. So it acts like a regular, pre-built, message.
There's actually something called "suggested actions" which is basically this, but dyanamic (i.e. you can pass it alongside your message). The user can click on these suggestions and it'll do the same -- put it in the compose box that the user then needs to send.

The biggest downside with the current method is that in a group-chat, everyone sees the slash-message. In a DM it doesn't really matter that much.

I will say that there are some more things coming soon that will enable better slash-command like experience soon.

@heyitsaamir
Copy link
Author

btw @bensabic I refactored a bit to split the giant index.ts into two files. Hope that's okay. The first file was just getting wildly unwieldy.

Copy link
Contributor

@bensabic bensabic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@heyitsaamir finally had a chance to formally review it.

The Teams SDK migration is directionally good, but this PR currently introduces a few blocking regressions and leaves the repo in a failing state.

  1. The public adapter contract changes in a breaking way without a compatibility layer. @chat-adapter/teams is still on the 4.x line, but the exported config now switches from appId / appPassword / appTenantId / TEAMS_APP_* to clientId / clientSecret / tenantId / CLIENT_*. Existing consumers will break on upgrade, and the examples/docs are still inconsistent about which env vars actually work.

  2. The PR currently breaks local typecheck/test surfaces. packages/integration-tests fails typecheck because the replay helper still expects appId while several updated callers now pass clientId, and the Teams-heavy replay/integration subset is also failing on this branch. That needs to be fixed before we can trust the migration coverage.

  3. Channel-thread history regresses for ordinary Teams channel traffic. The new channel-context caching only persists state when channelData.team.aadGroupId is already present, but the recorded payloads in this repo only carry team.id. Without the old fallback/recovery path, thread-aware Graph reads fall back to the generic chat path instead of the proper channel-thread endpoints.

  4. WebhookOptions are now stored on shared adapter state during handleWebhook(). Since the adapter instance is reused across requests, overlapping webhooks can overwrite each other’s waitUntil before the async handlers consume it. That is a real concurrency bug for production webhook handling.

  5. Outgoing reaction support is incomplete. Incoming Teams reactions are normalized into Chat emoji names like thumbs_up, but outgoing reactions are sent back to Teams using emoji.name directly. That means common flows like echoing a received reaction back will send thumbs_up instead of the Teams token like.

  6. Env-only tenant autodetection does not fully reach proactive paths. openDM() and channel-info logic still read this.config.tenantId, but values resolved internally by the Teams SDK app are not copied back into adapter config. In practice, env-only setups can still fail until an inbound event has already cached tenant state.

@bensabic
Copy link
Contributor

Sweet. I'm happy to put up a PR stacked on this, or once this goes in (if y'all are okay with it).

As for slash commands - we currently have a version of it: https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/create-a-bot-commands-menu?tabs=desktop%2Cjavascript Here, it will suggest some slash commands for the user, and you declare them in your manifest. But triggering them essentially just dumps the command in your compose box. And the user needs to send them. So it acts like a regular, pre-built, message. There's actually something called "suggested actions" which is basically this, but dyanamic (i.e. you can pass it alongside your message). The user can click on these suggestions and it'll do the same -- put it in the compose box that the user then needs to send.

The biggest downside with the current method is that in a group-chat, everyone sees the slash-message. In a DM it doesn't really matter that much.

I will say that there are some more things coming soon that will enable better slash-command like experience soon.

Re: Modals, I'd say wait until this PR goes in, then we can cross that bridge when we come to it.

Re: Slash commands, I'd ideally rather wait to add support for that until the Teams SDK has slash commands which are closer to Slack functionality. Mainly so the UX is more familiar to users and consistent across platforms.

@heyitsaamir
Copy link
Author

Ah thanks for the closer look! Yeah I called out the breaking options in the description, so I'm happy to build a translation layer between the two.

Let me go through these suggestions, and get back to you :). Thanks Ben.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants